package www.reagnetbox.com.scan;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;


import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import static www.reagnetbox.com.scan.LogComm.printf;


/**通讯接口管理类，单例模式。通过设备描述获取匹配通讯接口
 * Created by lgz on 17-4-27.
 */

public class CommManage implements CommResCode {

	private Context mContext;
	private Map<String, Class<? extends CommDriver>> mSupportComm =
			new HashMap<String, Class<? extends CommDriver>>();

	List<CommUtilityDelegate> listDelegate = new ArrayList<>();
	private static CommManage mCommManage;
	private static Lock mLock = new ReentrantLock();
	private boolean logEnable = false;

	/**通讯模块log使能
	 *
	 * @param bEnable true开log
	 */
	public void setLogEnable(boolean bEnable) {
		logEnable = bEnable;
		LogComm.setEnable(logEnable);
	}

	public CommManage() {
		init();
	}

	/**获取obj
	 *
	 * @return CommManage obj
	 */
	public static CommManage getinstance() {

		if (mCommManage == null) {
			mLock.lock();
			if (mCommManage != null) {
				mLock.unlock();
				return mCommManage;
			}
			mCommManage = new CommManage();
			mLock.unlock();
		}
		return mCommManage;
	}

	/**
	 * 通过设备描述，获取设备通讯接口
	 * @param comm 设备描述obj
	 * @return 通讯接口obj
	 * @throws RuntimeException
	 */
	public CommAbility getComm(CommType comm) throws RuntimeException {
		if (comm == null || comm.mDescript == null) {
			throw new RuntimeException("comm is null");
//			return null;
		}

		if (mSupportComm == null || mSupportComm.size() == 0) {
			throw new RuntimeException("driver is null");
//			return null;
		}

		String dcript = comm.mDescript.getDescript();
		Class<? extends CommDriver> driverClass = mSupportComm.get(dcript);

		if (driverClass != null) {
			final CommDriver driver;
			try {
				final Constructor<? extends CommDriver> ctor =
						driverClass.getConstructor(Context.class, CommType.class);
				driver = ctor.newInstance(mContext, comm);
				return driver.getCommAbility();
			} catch (NoSuchMethodException e) {
				throw new RuntimeException(e);
			} catch (IllegalArgumentException e) {
				throw new RuntimeException(e);
			} catch (InstantiationException e) {
				throw new RuntimeException(e);
			} catch (IllegalAccessException e) {
				throw new RuntimeException(e);
			} catch (InvocationTargetException e) {
				throw new RuntimeException(e);
			}
		} else {
			throw new RuntimeException("not get driver");
		}

	}

	/**
	 * context用于注册系统usb、蓝牙广播
	 * @param context
	 */
	public void registerContext(Context context) {
		if (mContext != context) {
			if (mContext != null) {
				mContext.unregisterReceiver(receiver);
			}

			mContext = context;
			IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
			filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
			filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
			mContext.registerReceiver(receiver, filter);
		}
	}

	public void unregisterContext() {
		if (mContext != null) {
			mContext.unregisterReceiver(receiver);
		}
		mContext = null;
	}

	/**
	 * 自动添加通讯驱动接口
	 */
	private void init() {
//		addCommDriver(UsbPl2303Driver.class);
		addCommDriver(UsbCdcDriver.class);
		addCommDriver(UsbHidDriver.class);
	}

	/**
	 * 注册支持驱动接口
	 */
	private boolean addCommDriver(Class<? extends CommDriver> driverClass) {

		final Method method;

		try {
			final List<CommTypeDescript> descriptGet;
			Constructor cons = driverClass.getConstructor(Context.class, CommType.class);

			Object obj = cons.newInstance(mContext, null);

			method = driverClass.getMethod("getSupportCommType");

			descriptGet = (List<CommTypeDescript>) method.invoke(obj);
			if (descriptGet != null) {
				for (CommTypeDescript desc : descriptGet) {
					mSupportComm.put(desc.getDescript(), driverClass);
				}
			}
			return true;
		} catch (SecurityException e) {
			printf("e:" + e);
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			printf("e:" + e);
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			printf("e:" + e);
			e.printStackTrace();
		} catch (InstantiationException e) {
			printf("e:" + e);
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			printf("e:" + e);
			e.printStackTrace();
		}
		return false;

	}

	/**
	 * 注册监听接口，监听usb插拔、权限状态，蓝牙断开。
	 * @param deledate 监听接口
	 */
	public void addListener(CommUtilityDelegate deledate) {
		if (deledate != null) {
			if (listDelegate.indexOf(deledate) == -1) {
				listDelegate.add(deledate);
			}
		}
	}

	/**
	 * 删除监听接口
	 * @param deledate
	 */
	public void removeListener(CommUtilityDelegate deledate) {
		if (deledate != null) {
			listDelegate.remove(deledate);
		}
	}

	private BroadcastReceiver receiver = new BroadcastReceiver() {
		@Override
		public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();
			printf("usbReceiver:" + action);

			if (ACTION_USB_PERMISSION.equals(action)) {

				UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
				boolean granted = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED,
						false);

				if (listDelegate != null && listDelegate.size() > 0) {
					for (CommUtilityDelegate delegate : listDelegate) {
						delegate.onUsbPermission(device, granted);
					}
				}

			} else if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {

				UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

				printf("USB_POINT device attached");

				if (listDelegate != null && listDelegate.size() > 0) {
					for (CommUtilityDelegate delegate : listDelegate) {
						printf("delegate:" + delegate);

						delegate.onUsbAttach(device);
					}
				}

			} else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
				UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

				printf("USB_POINT device detached:" + device);

				if (listDelegate != null && listDelegate.size() > 0) {
					for (CommUtilityDelegate delegate : listDelegate) {
						delegate.onUsbDettach(device);
					}
				}
			}
		}
	};
}
